package com.ddyang.Webflux.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class NioServer {

    private static Map<String, SocketChannel> clientMap = new HashMap();

    public static void main(String[] args) throws IOException {
        // 打开一个通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        // 通道创建socket绑定特定端口
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(8899));

        // 注册selector准备接收网络消息
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            System.out.println("监听中...........");
            try {

                selector.select();
                // 查找已绑定的key
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                // 对每个key做如下操作
                selectionKeys.forEach(selectionKey -> {
                    final SocketChannel client;

                    try {
                        if (selectionKey.isAcceptable()) {
                            System.out.println("------------>>>>链接成功");
                            client = NioUtil.acceptClient(selector, selectionKey);

                            String key = "【" + UUID.randomUUID().toString() + "】";
                            clientMap.put(key, client);
                        } else if (selectionKey.isReadable()) {
                            System.out.println("-------->>>>>开始读取信息");

                            client = (SocketChannel) selectionKey.channel();
                            String receivedMessage = NioUtil.readMessage(client);
                            System.out.println(client + ": " + receivedMessage);
                            NioUtil.writeMessage(client, "向client返回相同消息:" + receivedMessage);
//                                writeMessage2AllClient(client,receivedMessage);
                        }
                        /**
                         *
                         * 为什么没有isWritable
                         * key.isWritable()是表示Socket可写,网络不出现阻塞情况下,一直是可以写的,所认一直为true.一般我们不注册OP_WRITE事件.
                         *
                         */
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                });

                selectionKeys.clear();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 会将一个client发送的信息广播给所有客户端
     *
     * @param client
     */
    private static void writeMessage2AllClient(SocketChannel client, String receivedMessage) throws IOException {
        String senderKey;
        for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
            if (client == entry.getValue()) {
                senderKey = entry.getKey();
                break;
            }
        }

        for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
            SocketChannel value = entry.getValue();

            ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

            writeBuffer.put((receivedMessage).getBytes());
            writeBuffer.flip();

            value.write(writeBuffer);
            System.out.println("向client返回相同消息:" + receivedMessage);

        }
    }


}